#!/bin/sh
# 
# 
SCRIPT_NAME='spam-check'
VERSION='0.3.4'
DESCRIPTION='SpamCheck - скрипт для проверки IP-адресов по спам базам'
AUTHOR='(C) 2010 Roman (Angel2S2) Shagrov'
EMAIL='angel2s2ru@gmail.com'
JABBER='angel2s2ru@jabber.org'
BLOG='http://angel2s2.blogspot.com/'
LICENSE='GPLv3'
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#       
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#       
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.
#
# 
# Обо всех ошибках, замечаниях и предложениях пишите на angel2s2ru@gmail.com 
# или оставляйте комментарии в моем блоге http://angel2s2.blogspot.com/
# 
# Благодарности:
# slash (http://linsovet.com/user/113)
# Tenno Seremel (http://serenareem.net/)
# ramok (http://linsovet.com/users/ramok)
# darkk (http://darkk.net.ru/)
# _gaSh_ (http://linsovet.com/users/gash)
# Silver Ghost (http://silverghost.org.ua) 
# 
# История изменений ( - - удалено; + - добавлено; = - изменено):
# 
# ToDo Version 0.3.5
# + Вывод не только на консоль, но и в logger (для отправки вывода в файл или в syslog)
# + Обработка "алиасов" (как правило это MX-записи в DNS-сервере)
#
# Version 0.3.4
# = Немного подправил хелп (--help)
# = В некоторых местах заменил sed на for, чтобы не делать лишнии циклы
#
# Version 0.3.3
# = Весь вывод предварительно пропускается через iconv, чтобы сконвертировать UTF-8 в системную локаль
# = Исправлена ошибка, связанная с не совсем корректно обработкой ответов от DNS-серверов (NXDOMAIN и IP-адреса)
# + Теперь DNS-сервер берется из /etc/resolv.conf, если такого файла нет или в нем нет записей, или ни один из них не пингуется, то по умолчанию используется OpenDNS (208.67.222.222)
#
# Version 0.3.2:
# = Добавлена более подробная инфа, отображаемая в случае "не известной" ошибки<br><br><br>
# 
# Version 0.3.1:
# + Пофиксен баг, из-за которого не верно обрабатывались некоторые ответы от DNSBL
# 
# Version 0.3.0:
# = Скрипт снова перписан с нуля
# = Теперь работает через интерпритатор sh, а не bash, как в пред. версиях
# = Узменены ключи запуска
# = Работать с "вшитым" списком по умолчанию, если не задано иное
# + "Вшитый" список DNSBL и ключ -l
# + Проверка, чтобы опции не пересекались, т.е. не допустить одновременного использования двух и более взаимоисключаемых опций
# + Выводить ошибки в поток ошибок
# - Временный файл больше не нужен
# - Убран цветной вывод результатов работы
# 
# Version 0.2.1:
# + Защита запуска из под root'а
# + Ключ -u для запуска из под root'а
# = Временный файл теперь генерится с помощью mktemp
# 
# Version 0.2.0:
# = Полноситью переписал скрипт, теперь он работает напрямую через dnsbl
# 
# Version 0.1.0:
# Первая публичная версия, работала по http.
# 

SED='/bin/sed'
WGET='/usr/bin/wget'
HOST='/usr/bin/host'
ICONV='/usr/bin/iconv -t UTF-8 '
PING='/bin/ping -c 1 '

# "Вшитый" список DNSBL для проверки
DNSBL_LIST='abuse.rfc-ignorant.org access.redhawk.org aspews.ext.sorbs.net b.barracudacentral.org blackholes.brainerd.net blackholes.five-ten-sg.com blackholes.wirehub.net blacklist.junkemailfilter.com blacklist.sci.kun.nl blacklist.woody.ch bl.deadbeef.com bl.emailbasura.org block.dnsbl.sorbs.net bl.redhatgate.com bl.spamcannibal.org bl.spamcop.net bl.technovision.dk c10.rbl.hk cbl.abuseat.org cbl.anti-spam.org.cn cblless.anti-spam.org.cn cblplus.anti-spam.org.cn combined.njabl.org db.wpbl.info dialups.mail-abuse.org dialups.visi.com dnsbl-0.uceprotect.net dnsbl-1.uceprotect.net dnsbl-2.uceprotect.net dnsbl-3.uceprotect.net dnsbl.ahbl.org dnsbl.cyberlogic.net dnsbl.jammconsulting.com dnsbl.kempt.net dnsbl.njabl.org dnsbl.sorbs.net duinv.aupads.org dul.dnsbl.sorbs.net dul.ru fl.chickenboner.biz hil.habeas.com hostkarma.junkemailfilter.com http.dnsbl.sorbs.net http.opm.blitzed.org images.rbl.msrbl.net ips.backscatterer.org ircbl.ahbl.org ix.dnsbl.manitu.net korea.services.net l2.bbfh.ext.sorbs.net list.dnswl.org mail-abuse.blacklist.jippg.org map.spam-rbl.com misc.dnsbl.sorbs.net msgid.bl.gweep.ca multi.surbl.org multi.uribl.com no-more-funn.moensted.dk ohps.dnsbl.net.au omrs.dnsbl.net.au orid.dnsbl.net.au orvedb.aupads.org osps.dnsbl.net.au osrs.dnsbl.net.au owfs.dnsbl.net.au owps.dnsbl.net.au pbl.spamhaus.org phishing.rbl.msrbl.net probes.dnsbl.net.au proxy.bl.gweep.ca psbl.surriel.com query.bondedsender.org rbl.cluecentral.net rbl-plus.mail-abuse.org rbl.snark.net rdts.dnsbl.net.au relays.bl.gweep.ca relays.bl.kundenserver.de relays.mail-abuse.org relays.nether.net ricn.dnsbl.net.au rmst.dnsbl.net.au rot.blackhole.cantv.net rsbl.aupads.org satos.rbl.cluecentral.net sbl.csma.biz sbl.spamhaus.org sbl-xbl.spamhaus.org smtp.dnsbl.sorbs.net socks.dnsbl.sorbs.net socks.opm.blitzed.org sorbs.dnsbl.net.au spam.dnsbl.sorbs.net spamguard.leadmon.net spam.olsentech.net spamrbl.imp.ch spamsites.dnsbl.net.au spamsources.dnsbl.info spamsources.fabel.dk spam.wytnij.to t1.bl.dnsbl.net.au t1.dnsbl.net.au ubl.unsubscore.com ucepn.dnsbl.net.au virbl.bit.nl virbl.dnsbl.bit.nl virus.rbl.jp virus.rbl.msrbl.net web.dnsbl.sorbs.net whois.rfc-ignorant.org wingate.opm.blitzed.org wormrbl.imp.ch wpbl.dnsbl.net.au xbl.spamhaus.org zen.spamhaus.org zombie.dnsbl.sorbs.net'

# Параметры по умолчанию
IS_QUIET=0					# -q	- Ничего не выводить
IS_DNSBL_PRINT=0			# -l	- Вывести список dnsbl-серверов
IS_ONE_DNSBL=0				# -d	- Указатель, что надо проверить по указанному DNSBL
IS_FILE=0					# -f	- Указатель, что используется файл
IS_INET=0					# -i	- Сграбить список DNSBL с сайта http://myiptest.com/
IP_LIST=''					#		- Тут будут все IP'шники 
IS_TIME_OUT_ERROR=0			# -t	- Считать тайм ауты подключения к DNSBL ошибками и выводить в поток ошибок?
DNS_SERVER='208.67.222.222'	# -s	- DNS Server (OpenDNS.com), через который будет проверяться IP по DNSBL
RESOLVCONF='/etc/resolv.conf'



#  name		Конвертирует строку в текущую локаль из UTF-8 и выводит строку на стандартный поток либо поток ошибок
#  $1		Строка, котору надо вывести (надо заключать в кавычки, если есть пробельные символы)
#  $2		Куда выводить (stduot (1)  или stderr (2))
#  output	Возвращает указанную строку ($1) выводя ее на stdout или stderr
#  return	0
_output() {
	# Если обычный режим, то выводим инфу на консоль, иначе просто все игнорируем
	if [ $IS_QUIET -eq 0 ] ; then
		if [ $1 -eq 2 ] ; then
			echo "$2" | $ICONV 1>&2
		else
			echo "$2" | $ICONV
		fi
	fi
}

#  name		Версия, копирайт, лицензия, контакты
#  output	--//--
#  return	0 
_version() {
	_output 1 "$SCRIPT_NAME, version $VERSION"
	_output 1 "Copyright $AUTHOR"
	_output 1 "License $LICENSE"
	_output 1 "Contacts: $EMAIL | $JABBER | $BLOG"
}

#  name		"Правила" использования скрипта
#  output	--//--
#  return	0
_usage() {
	_output 1 "$SCRIPT_NAME [-q] [-l] [-d dnsbl | -f filename | -i] [-s dns_server] [-t] [-w] [--] [ip or domain-name ...]"
}

#  name		Справка по использованию параметров скрипта
#  output	--//--
#  return	0
_help() {
	_usage
	_output 1 ""
	_output 1 "   -q		- Ничего не выводить"
	_output 1 "   -l		- Показать список DNSBL-серверов"
	_output 1 "   -d		- Проверить по указанному DNSBL"
	_output 1 "   -f		- Взять список DNSBL-серверов из файла (по одному на строчку)"
	_output 1 "   -i		- Сграбить список DNSBL с сайта http://myiptest.com/"
	_output 1 "   -s		- Указать DNS-сервер, через который будет идти проверка"
	_output 1 "   -t		- Считать Time Out'ы ошибкой"
	_output 1 "   --		- Считается, что дальше идут только ip и/или доманные имена"
	_output 1 "   [ip or domain-name ...]	- ip и/или доменный имена, которые нужно проверить"
	_output 1 "   --version, --help, --usage	- без комментариев"
}

#  name		Сообщение о не известном/не верном параметре переданном скрипту	
#  output	--//--
#  return	0
_bad_param() {
	_output 2 "Не известный параметр: $1"
}

#  name		Проверяет, является ли переданый парамерт ip-адресом и, если да, заносит его в переменную $IP_LIST
#  $1		ip-адрес
#  output	none
#  return	0
_check_and_build_ip_list() {
	CBL=$(echo "$1" | $SED -n '/[^0-9\.]\+/p')
	# если пусто, значит считаем что у нас "IP"
	if [ -z "$CBL" ] ; then 
		IP_LIST="$IP_LIST $1"
	# иначе "доменное имя"
	else
		IP_LIST="$IP_LIST $($HOST $1 | $SED -n '/address/s/^.\+\ \([0-9\.]\+\).*$/\1/gp')"
	fi
}

# Парсим параметры запуска
if [ $# -eq 0 ] ; then _help ; exit 1 ; fi
while [ $# -gt 0 ]; do
	case "$1" in
		"-q"	) IS_QUIET=1 ; shift ;;
		"-t"	) IS_TIME_OUT_ERROR=1 ; shift ;;
		"-f"	) IS_FILE=1 ; if [ -r "$2" ] ; then DNSBL_LIST=$($SED '/^$/d' $2) ; shift 2 ; else _output 2 "Файл $2 либо не существует, либо нет прав на чтение!" ; exit 1 ; fi ;;
		"-i"	) IS_INET=1 ; DNSBL_LIST=$($WGET -q -O - 'http://www.myiptest.com/staticpages/index.php/check-Blacklisted-IP-DNSBL/'$DNS_SERVER | $SED -n '/href=.\+dnsbl=/s/^.\+dnsbl=\([a-zA-Z0-9\.\-]\+\).*$/\1/gp') ; shift ;;
		"-d"	) IS_ONE_DNSBL=1 ; DNSBL_LIST=$2 ; shift 2 ;;
		"-l"	) IS_DNSBL_PRINT=1 ; shift ;;
		"-s"	) DNS_SERVER=$2 ; shift 2 ;;
		"--"	) shift ; while [ $# -gt 0 ] ; do _check_and_build_ip_list $1 ; shift ; done ; break ;;
		"--version"	) _version ; exit 255 ;;
		"--help"	) _help ; exit 255 ;;
		"--usage"	) _usage ; exit 255 ;;
		-*		) _bad_param $1 ; exit 1 ;;
		*		) _check_and_build_ip_list $1 ; shift ;;
	esac
done

# Список DNSBL-серверов заполнен?
if [ -z "$DNSBL_LIST" -a $IS_INET -eq 1 ] ; then _output 'Список DNSBL-серверов пуст! Видать не удалось подкючиться к северу.' 2 ; fi
if [ -z "$DNSBL_LIST" -a $IS_FILE -eq 1 ] ; then _output 'Список DNSBL-серверов пуст! Видать файл пустой.' 2 ; fi
if [ -z "$DNSBL_LIST" ] ; then _output 'Список DNSBL-серверов пуст! Ты случаем в скрипте переменную $DNSBL_LIST не удалил?' 2 ; fi


#  name		Выводит сообщение "Не совместимые параметры!"
#  output	--//--
#  return	0
_bad_params_combine() {
	_output 2 "Не совместимые параметры!"
	exit 1
}

# Проверка на (не)совместимость параметров
if [ $IS_DNSBL_PRINT -gt 0 -a $IS_QUIET -gt 0 ] ; then _bad_params_combine ; fi
if [ $IS_FILE -gt 0 -a $IS_INET -gt 0 ] ; then _bad_params_combine ; fi
if [ $IS_FILE -gt 0 -a $IS_ONE_DNSBL -gt 0 ] ; then _bad_params_combine ; fi
if [ $IS_ONE_DNSBL -gt 0 -a $IS_INET -gt 0 ] ; then _bad_params_combine ; fi

# Вывод списка DNSBL серверов, если на то был "запрос"
if [ $IS_DNSBL_PRINT -gt 0 ] ; then echo "$DNSBL_LIST" | $SED 's/\ /\n/g' | $SED '/^$/d' ; exit 0 ; fi

#  name		"Переворачивает" переданный ip-адрес и возвращает его
#  $1		ip-адрес
#  output	"Перевернутый" ip-адрес
#  return	0
_reverse_ip() {
	echo $1 | $SED -e 's/$/\n/;:z;s/\([0-9]\{1,3\}\)\([^\n]*\n\)/\2\1./;tz;s/.*\n//;s/.$//'
}

#  name		Получает ответ от DNSBL сервера, парсит его и выводим соответствующую информацию
#  $1		"Перевернутый" ip-адрес для проверки
#  output	Сообщение о результате проверки
#  return	0 or 1
_get_and_parse_dnsbl_return() {
	for DNSBL in $DNSBL_LIST ; do
		GPD=$($HOST -t A $1.$DNSBL $DNS_SERVER)
		RES_A=$(echo "$GPD" | $SED -n '/not\ found/p')
		# Нас нет в DNSBL :)
		if [ -n "$RES_A" ] ; then
			_output 1 "[ OK ]         - $DNSBL		- $(echo $RES_A | $SED 's/^.*\(not\ found.\+$\)/\1/')"
		else
			RES_A=$(echo "$GPD" | $SED -n '/\ has\ address\ /s/^.*address\ \([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).*$/\1/p')
			# Черт... У нас проблемы :(
			if [ -n "$RES_A" ] ; then
				# Узнаем подробности
				RES_TXT=$($HOST -t TXT $1.$DNSBL $DNS_SERVER | $SED -n '/text/s/^.*\"\(.\+\)\".*$/\1/p')
				_output 2 "[ +++SPAM+++ ] - $DNSBL		- ($RES_A) $RES_TXT"
				RETURN_CODE=1
			else
				# Или может мы просто не можем достучаться до DNSBL-сервера?
				RES_A=$(echo "$GPD" | $SED -n '/connection timed out/p')
				if [ -n "$RES_A" ] ; then
					if [ $IS_TIME_OUT_ERROR -gt 0 ] ; then
						_output 2 "[ ERROR ]      - $DNSBL		- connection time out"
					 	RETURN_CODE=1
					else
						_output 1 "[ ERROR ]      - $DNSBL		- connection time out"
					fi
				else
					_output 'Странно... Ты не должен был этого видеть... о_О Напиши мне багрепорт, плиз, укажи версии sh, sed, host и самого скрипта, а так же какая у тебя ось и какие параметры были переданы скрипту. Заранее спасибо. Мое мыло: angel2s2ru@gmail.com' 2
					RETURN_CODE=1
				fi
			fi
		fi
		done
		return $RETURN_CODE
}

# IP указан?
if [ -z "$IP_LIST" ] ; then _output 2 "Не указаны адреса для проверки!" ; exit 1 ; fi

# Если есть в системе resolv.conf...
if [ -r $RESOLVCONF ] ; then 
	# ...выдираем из него IP'шники DNS-серверов...
	NS=$($SED -n '/nameserver/s/nameserver[\ \t]\+\([0-9\.]\+\)/\1/p' $RESOLVCONF)
	# ...и проверяем их на доступность...
	for NS_CURRENT in $NS ; do
		# ...если хоть один доступен...
		$PING $NS_CURRENT >/dev/null 2>&1
		if [ $? -eq 0 ] ; then
			# ...то будем юзать его
			DNS_SERVER=$NS_CURRENT
			break
		fi
	done
fi	# В противном случае будет использоваться DNS-сервер по дефолту (см. переменную $DNS_SERVER в разделе "Параметры по умолчанию")

for IP in $IP_LIST ; do
	# Получаем "перевернутый" IP
	R_IP=$(_reverse_ip $IP)
	_output 1 "------------------------------------------$IP------------"
			# Проверяем наши IP по спам-базам и выводим результат на консоль
			_get_and_parse_dnsbl_return $R_IP
			EXIT_CODE=$?
done
exit $EXIT_CODE

